﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MaxLeaf.Platform.Contract;
using MaxLeaf.Platform.DataContract;
using MaxLeaf.Platform.DALImplementation;
using MaxLeaf.Platform.BRL;
using CommonsLib.DB;
using CommonsLib.Settings;
using MaxLeaf.Platform.Functions;
using System.Collections;
using MaxLeaf.Platform.Commons;
using CommonsLib.Utility;

namespace MaxLeaf.Platform.BLLImplementation
{
    public class BaseBLL  :IMtn
    {
        
        protected string DataModelTypeName
        {
            get;
            set;
        }
        public BaseBLL()
        {
           DataModelTypeName =this.GetType().Name.Replace( "BLL","DataModel");
        }
        public BaseBLL(string strDataModelTypeName)
        {
            DataModelTypeName = strDataModelTypeName;
        }
         



        private BaseBRL _brl = null;
        public BaseBRL CurrentBRL
        {
            get
            {
                if (_brl == null)
                {
                    _brl = GetBRL(this.DataModelTypeName);
                }
                return _brl;
            }
        }
        private BaseDAL _dal = null;
        public BaseDAL CurrentDAL
        {
            get
            {
                if (_dal == null)
                {
                    _dal = GetDAL(this.DataModelTypeName);
                }
                return _dal;
            }
        }
         

         /// <summary>
        /// 要取最大ID的字段
        /// </summary>
        public virtual string FinterIDFields
        {
            get
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 要取最大单号的字段
        /// </summary>
        public virtual string BillNoFields
        {
            get
            {
                return string.Empty;
            }
        }

        

        private static readonly Dictionary<string, Type> _dictBLL = new Dictionary<string, Type>();
        private static readonly Dictionary<string, Type> _dictBRL = new Dictionary<string, Type>();
        private static readonly Dictionary<string, Type> _dictDAL = new Dictionary<string, Type>();

        public static BaseBLL GetDataModelBLL(string strModelTypeName)
        {
            lock (_dictBLL)
            {
                

                if (!_dictBLL.ContainsKey(strModelTypeName))
                {
                    BaseBLL bll;
                    Type type = Type.GetType(string.Format("{0}.{1},{0}", "MaxLeaf.Platform.BLLImplementation", strModelTypeName.Replace("DataModel", "BLL")), false, true);
                    if (type == null)
                    {
                        _dictBLL[strModelTypeName] = typeof(BaseBLL);
                        bll = new BaseBLL(strModelTypeName);
 
                    }
                    else
                    {
                        _dictBLL[strModelTypeName] = type;
                        if (type.Name.Equals("BaseBLL"))
                        {
                            bll = (BaseBLL)System.Activator.CreateInstance(type, strModelTypeName);
                        }
                        else
                        {
                            bll = (BaseBLL)System.Activator.CreateInstance(type);
                        }
 
                    }

                    return bll;
                }
                else
                {
                    if (_dictBLL[strModelTypeName].Name.Equals("BaseBLL"))
                    {
                        return (BaseBLL)System.Activator.CreateInstance(_dictBLL[strModelTypeName], strModelTypeName);
                    }
                    else
                    {
                        return (BaseBLL)System.Activator.CreateInstance(_dictBLL[strModelTypeName]);
                    }

                }
            }
        }
        private static BaseBRL GetBRL(string strModelTypeName)
        {
            
            lock (_dictBRL)
            {
                

                if (!_dictBRL.ContainsKey(strModelTypeName))
                {

                    Type type = Type.GetType(string.Format("{0}.{1},{0}", "MaxLeaf.Platform.BRL", strModelTypeName.Replace("DataModel", "BRL")), false, true);
                    if (type == null)
                    {
                        _dictBRL[strModelTypeName] = typeof(BaseBRL);
                        return new BaseBRL();
                    }
                    else
                    {
                        _dictBRL[strModelTypeName] = type;
                        return (BaseBRL)System.Activator.CreateInstance(type);
                    }
                }
                else
                {

                    return (BaseBRL)System.Activator.CreateInstance(_dictBRL[strModelTypeName]);

                }
            }
        }
        private static BaseDAL GetDAL(string strModelTypeName)
        {
             
            lock (_dictDAL)
            {
 

                if (!_dictDAL.ContainsKey(strModelTypeName))
                {

                    Type type = Type.GetType(string.Format("{0}.{1},{0}", "MaxLeaf.Platform.DALImplementation", strModelTypeName.Replace("DataModel", "DAL")), false, true);
                    if (type == null)
                    {
                        _dictDAL[strModelTypeName] = typeof(BaseDAL);
                        return new BaseDAL();
                    }
                    else
                    {
                        _dictDAL[strModelTypeName] = type;
                        return (BaseDAL)System.Activator.CreateInstance(type);
                    }
                }
                else
                {

                    return (BaseDAL)System.Activator.CreateInstance(_dictDAL[strModelTypeName]);

                }
            }
        }

        public virtual object Select(object model, int intKeyValue)
        {
            string strKeyName = DataFunc.GetKeyField(model);
            List<object> lst = SelectByCond(model
                    , new List<AddInfo>() { 
                        new AddInfo{ Name= AddInfoType.Cond ,Value= new List<Cond>() { 
                                new Cond { PropName =DataFunc.GetPropName(model, strKeyName), Compare = CompareType.Equal, Value = intKeyValue }
                            }
                        } 
                    }                    
                ).Data;
            if (lst.Count > 0)
            {
                return lst[0];
            }
            return null;
            
        }

        public virtual List<object> SelectDtl(object model, int intForeignKeyValue)
        {
            string strForeignKeyName = DataFunc.GetForeignKeyField(model);
            
            return SelectByCond(model
                , new List<AddInfo>() { 
                        new AddInfo{ Name= AddInfoType.Cond ,Value= new List<Cond>() { 
                                new Cond { PropName =DataFunc.GetPropName(model, strForeignKeyName)
                                    , Compare = CompareType.Equal
                                    , Value = intForeignKeyValue 
                                } 
                            }
                        } 
                    }
                    
                
                ).Data;
            
            
        }
        public virtual SelectResult SelectByCond(object model, List<AddInfo> lstAddInfo)
        {
            Type modelType=model.GetType();
            if (!this.DataModelTypeName.Equals(modelType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }
            List<object> lstModels = null;

            List<Cond> lstCond = null;
            List<SortBy> lstSortBy = null;
            //List<LazySubTable> lstLazySubTable = null;
            List<FieldFilter> lstFieldFilter = null;
            PageInfo pageInfo = null;
            List<SumInfo> lstSumInfo = null;
            if (lstAddInfo != null && lstAddInfo.Count > 0)
            {
                GetAddInfo(lstAddInfo, ref lstCond, ref lstSortBy, ref lstFieldFilter, ref pageInfo, ref lstSumInfo);
            }


            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
            {
                


                lstModels = CurrentDAL.SelectByCond(dbcon, model, lstCond, lstSortBy, lstFieldFilter, ref pageInfo);

                
            }

            //SetSubTableData(  model,  lstModels, lstLazySubTable);

            return new SelectResult { Data = lstModels, TotalCount = (pageInfo==null?lstModels.Count: pageInfo.TotalCount), TotalPageCount = (pageInfo==null?1:pageInfo.TotalPageCount) };

        }


        public virtual SumResult Sum(object model, List<AddInfo> lstAddInfo)
        {
            Type modelType=model.GetType();
            if (!this.DataModelTypeName.Equals(modelType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }

            List<double> lstData= null;

            List<Cond> lstCond = null;
            List<SortBy> lstSortBy = null;
            //List<LazySubTable> lstLazySubTable = null;
            List<FieldFilter> lstFieldFilter = null;
            PageInfo pageInfo = null;
            List<SumInfo> lstSumInfo = null;
            
            
            if (lstAddInfo != null && lstAddInfo.Count > 0)
            {
                GetAddInfo(lstAddInfo, ref lstCond, ref lstSortBy, ref lstFieldFilter, ref pageInfo,ref   lstSumInfo);
            }
            if (lstSumInfo == null)
            {
                return null;
            }

            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
            {
                


                lstData= CurrentDAL.Sum(dbcon, model, lstCond, lstSumInfo);


            }

            return new SumResult { Data = lstData };
        }

        private void GetAddInfo(List<AddInfo> lstAddInfo, ref List<Cond> lstCond, ref List<SortBy> lstSortBy , ref List<FieldFilter> lstFieldFilter, ref PageInfo pageInfo,ref List<SumInfo> lstSumInfo)
        {
            foreach (AddInfo addInfo in lstAddInfo)
            {
                switch (addInfo.Name )
                {
                    case AddInfoType.Cond:
                        lstCond = (List<Cond>)addInfo.Value;
                        break;
                    case AddInfoType.SumInfo:
                        lstSumInfo = (List<SumInfo>)addInfo.Value;
                        break;
                    case AddInfoType.SortBy:
                        lstSortBy = (List<SortBy>)addInfo.Value;
                        break;
                    //case AddInfoType.LazySubTable:
                    //    lstLazySubTable = (List<LazySubTable>)addInfo.Value;
                    //    break;
                    case AddInfoType.FieldFilter:
                        lstFieldFilter = (List<FieldFilter>)addInfo.Value;
                        break;
                    case AddInfoType.PageInfo:
                        pageInfo = (PageInfo)addInfo.Value;
                        break;
                    default:
                        throw new MaxLeaf.Platform.Commons.MaxLeafException(string.Format("AddInfoType {0} 未实现",addInfo.Name));
                }
            }
        }

        //private void SetSubTableData( object model,  List<object> lstModels, List<LazySubTable> lstLazySubTable)
        //{
        //    if (lstLazySubTable == null || lstLazySubTable.Count == 0) return;

        //    string[] arrLazySubTable = GetLazySubTable(lstLazySubTable);

        //    string strSubTables = DataFunc.GetSubTables(model);

        //    if (strSubTables.Length > 0)
        //    {
                
        //        string[] arrSubTables = strSubTables.Split(',');
        //        for (int i = 0; i < arrSubTables.Length; i++)
        //        {
        //            string[] arrSubTable = arrSubTables[i].Split('|');

        //            if (!arrLazySubTable.Contains(arrSubTable[0]))
        //            {
        //                continue;
        //            }

        //            System.Reflection.PropertyInfo prop = model.GetType().GetProperty(arrSubTable[0]);
        //            if (prop == null)
        //            {
        //                break;
        //            }

        //            bool blnIsList = false;
        //            if (prop.PropertyType.IsGenericType)
        //            {
        //                blnIsList = true;
        //            }
        //            Dictionary<string, object> dictSubTable = new Dictionary<string, object>();
        //            foreach (object obj in lstModels)
        //            {
        //                object strOrgValue = DataFunc.GetValue(obj, arrSubTable[1]);
        //                string strSubTableKey = string.Format("{0}|{1}", arrSubTable[0], strOrgValue);
        //                object subtableModel = null;
        //                if (dictSubTable.ContainsKey(strSubTableKey))
        //                {
        //                    subtableModel = dictSubTable[strSubTableKey];
        //                }
        //                else
        //                {
        //                    List<object> lstSubTableModels = null;
        //                    object submodel = System.Activator.CreateInstance(blnIsList ? prop.PropertyType.GetGenericArguments()[0] : prop.PropertyType);
                             
        //                        lstSubTableModels = this.SelectByCond( submodel
        //                            ,new List<AddInfo>(){
        //                                    new AddInfo{ Name= AddInfoType.Cond ,Value= new List<Cond> {
        //                                                new Cond{ PropName=arrSubTable[2],Compare= CompareType.Equal , Value =strOrgValue}
        //                                            }
        //                                    }
        //                            }
        //                            ).Data;
                            
        //                    if (blnIsList)
        //                    {

        //                        subtableModel = BaseFunc.CreateGeneric(typeof(List<>), submodel.GetType());
        //                        foreach (object subobj in lstSubTableModels)
        //                        {
        //                            ((IList)subtableModel).Add(subobj);
        //                        }


        //                    }
        //                    else
        //                    {
        //                        if (lstSubTableModels == null || lstSubTableModels.Count == 0)
        //                        {
        //                            subtableModel = null;
        //                        }
        //                        else
        //                        {
        //                            subtableModel = lstSubTableModels[0];
        //                        }
        //                    }

        //                    dictSubTable.Add(strSubTableKey, subtableModel);
        //                }
        //                prop.SetValue(obj, subtableModel, null);
        //            }

        //        }

        //    }
        //}

        //private  string[] GetLazySubTable(List<LazySubTable> lstLazySubTable)
        //{
        //    if (lstLazySubTable == null || lstLazySubTable.Count == 0)
        //    {
        //        return null;
        //    }

        //    string[] arr = new string[lstLazySubTable.Count];
        //    for (int i = 0; i < lstLazySubTable.Count; i++)
        //    {
        //        arr[i] = lstLazySubTable[i].PropName;
        //    }

        //    return arr;
        //}





        public virtual object Add(object model)
        {
            Type modelType=model.GetType();
            if (!this.DataModelTypeName.Equals(modelType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }

            if (string.IsNullOrEmpty(this.FinterIDFields))
            {
                SetFInterID(model);
                SetBillNo(model);
                using (System.Transactions.TransactionScope ts = DataFunc.CreateTransactionScope())
                {
                    using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
                    {

                        model= Add(dbcon, model);

                    }
                    ts.Complete();
                    return model;
                }
            }
            else
            {
                model = InsertFinterID(model);
                try
                {
                    return Update(model);
                }
                catch
                {
                    //删除插入的id
                    using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
                    {
                        CurrentDAL.Delete(dbcon, model);
                    }
                    throw;
                }

            }
        }

        public object InsertFinterID(object model)
        {
            Type modelType=model.GetType();
            if (!this.DataModelTypeName.Equals(modelType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }

            SetFInterID(model);
            SetBillNo(model);

            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
            {

                model = CurrentDAL.InsertFinterID(dbcon, model, GetFinterIDFieldName(this.FinterIDFields));


            }
            return model;
        }

        protected string GetFinterIDFieldName(string strFinterIDFields)
        {
            List<string> lstFields = new List<string>();
            string[] arrFields = strFinterIDFields.Split('|');
            foreach (string strFields in arrFields)
            {
                string[] arrField = strFields.Split(',');
                lstFields.Add(arrField[0]);                
            }

            return string.Join(",", lstFields.ToArray());
        }

        public object Add(DBAccess dbcon, object model)
        {
            //if (blnNeedTrans) dbcon.BeginTrans();
            try
            {
                Add_BeforeValid(dbcon, model);
                if (CurrentBRL.AddValid(dbcon, CurrentDAL, model))
                {
                    model = CurrentDAL.Add(dbcon, model);

                    Add_After(dbcon, model);
                    //if (blnNeedTrans) dbcon.CommitTrans();

                    return model;
                }

                throw new MaxLeaf.Platform.Commons.MaxLeafException(string.Format("无法增加记录 {0}!", model));

            }
            catch (Exception ex)
            {
                //if (blnNeedTrans) dbcon.RollbackTrans();
                LogManager.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// 增加其他数据
        /// </summary>
        /// <param name="dbcon"></param>
        /// <param name="model"></param>
        protected virtual void Add_After(DBAccess dbcon, object model)
        {
            
        }

        protected virtual void Add_BeforeValid(DBAccess dbcon, object model)
        {
             
        }

        /// <summary>
        /// 默认billno
        /// </summary>
        /// <param name="model"></param>
        public void SetBillNo(object model)
        {
            if (string.IsNullOrEmpty(this.BillNoFields)) return;
            string[] arrFields = this.BillNoFields.Split('|');
            foreach (string strFields in arrFields)
            {
                string[] arrField = strFields.Split(',');
                DataFunc.SetValue(model
                    , DataFunc.GetBillNo((FinterIDType)CvtFunc.ToInt(arrField[1]), CvtFunc.ToInt(DataFunc.GetValue(model,"CompanyId")))
                    , arrField[0]
                    ,true
                );
            }
 
        }

        /// <summary>
        /// 默认finterid
        /// </summary>
        /// <param name="model"></param>
        public void SetFInterID(object model)
        {
            if (string.IsNullOrEmpty(this.FinterIDFields)) return  ;
            string[] arrFields = this.FinterIDFields.Split('|');
            foreach (string strFields in arrFields)
            {
                string[] arrField = strFields.Split(',');
                DataFunc.SetValue(model
                    , DataFunc.GetFinterID((FinterIDType)CvtFunc.ToInt(arrField[1]))
                    , arrField[0]
                    ,true
                );
            }


        }
        
        public virtual object Update(object model )
        {
            Type modelType=model.GetType();
            if (!this.DataModelTypeName.Equals(modelType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }

            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modelType))
            {
                using (System.Transactions.TransactionScope ts = DataFunc.CreateTransactionScope())
                {


                    model = Update(dbcon, model);

                    ts.Complete();


                }
                Update_AfterTrans(dbcon, model);
            }

            return model;

        }

        protected virtual void Update_BeforeValid(DBAccess dbcon, object model)
        {

        }

        public object Update(DBAccess dbcon, object model )
        {
            //if(blnNeedTrans) dbcon.BeginTrans();
            try
            {
                Update_BeforeValid(dbcon, model);
                if (CurrentBRL.UpdateValid(dbcon,CurrentDAL, model))
                {
                    model = CurrentDAL.Update(dbcon, model);

                    Update_After(dbcon, model);
                    //if (blnNeedTrans) dbcon.CommitTrans();

                    return model;
                }

                throw new MaxLeaf.Platform.Commons.MaxLeafException(string.Format("无法修改记录 {0}!", model));
            }
            catch (Exception ex)
            {
                //if (blnNeedTrans) dbcon.RollbackTrans();
                LogManager.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// 修改其他数据,不在事务里
        /// </summary>
        /// <param name="dbcon"></param>
        /// <param name="model"></param>
        protected virtual void Update_AfterTrans(DBAccess dbcon, object model)
        {

        }

        /// <summary>
        /// 修改其他数据
        /// </summary>
        /// <param name="dbcon"></param>
        /// <param name="model"></param>
        protected virtual void Update_After(DBAccess dbcon, object model)
        {
             
        }

        public virtual bool Delete(object model)
        {
            bool blnRT = false;
            Type modleType=model.GetType();
            if (!this.DataModelTypeName.Equals(modleType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }
            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modleType))
            {
                using (System.Transactions.TransactionScope ts = DataFunc.CreateTransactionScope())
                {


                    blnRT = Delete(dbcon, model);

                    ts.Complete();

                }

                Delete_AfterTrans(dbcon, model);
            }
            return blnRT;
        }
        public virtual bool Undelete(object model)
        {
            bool blnRT = false;
            Type modleType = model.GetType();
            if (!this.DataModelTypeName.Equals(modleType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }
            using (System.Transactions.TransactionScope ts = DataFunc.CreateTransactionScope())
            {
                using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modleType))
                {

                    blnRT = Undelete(dbcon, model);
                }
                ts.Complete();
                return blnRT;
            }
        }

        private bool Delete(DBAccess dbcon,object model )
        {

            //if (blnNeedTrans) dbcon.BeginTrans();
            try
            {
                if (CurrentBRL.DeleteValid(dbcon, CurrentDAL, model))
                {
                    bool blnRT = false;

                    if (DataFunc.ExistField(model, "is_delete"))
                    {
                        CurrentDAL.FakeDelete(dbcon, model);
                    }
                    else
                    {
                        CurrentDAL.Delete(dbcon, model);
                    }

                    
                    //if (blnNeedTrans) dbcon.CommitTrans();

                    return blnRT;
                }

                throw new MaxLeaf.Platform.Commons.MaxLeafException(string.Format("无法删除记录 {0}!", model));
            }
            catch
            {
                //if (blnNeedTrans) dbcon.RollbackTrans();
                throw;
            }
        }

        private bool Undelete(DBAccess dbcon, object model)
        {

            //if (blnNeedTrans) dbcon.BeginTrans();
            try
            {
                //if (CurrentBRL.DeleteValid(dbcon, CurrentDAL, model))
                //{
                    bool blnRT = false;

                    if (DataFunc.ExistField(model, "is_delete"))
                    {
                        CurrentDAL.FakeUndelete(dbcon, model);
                    }
                    else
                    {
                        
                    }

                    
                    //if (blnNeedTrans) dbcon.CommitTrans();

                    return blnRT;
                //}

                //throw new MaxLeaf.Platform.Commons.MaxLeafException(string.Format("无法反删除记录 {0}!", model));
            }
            catch
            {
                //if (blnNeedTrans) dbcon.RollbackTrans();
                throw;
            }
        }

        /// <summary>
        /// 删除其他数据
        /// </summary>
        /// <param name="dbcon"></param>
        /// <param name="model"></param>
        protected virtual void Delete_AfterTrans(DBAccess dbcon, object model)
        {
            
        }

         

        internal object GetFieldValue(object  model, int intKey, string strFieldName)
        {
            Type modleType = model.GetType();
            if (!this.DataModelTypeName.Equals(modleType.Name))
            {
                throw new MaxLeafException(string.Format("Wrong DataModelTypeName {0}", DataModelTypeName));
            }
            using (DBAccess dbcon = DataFunc.GetDBAccessByDataModelType(modleType))
            {

                return this.CurrentDAL.GetFieldValue(dbcon, model, intKey, strFieldName);
            }
        }
    }
}
